<?php

class File_Transfer_HttpWithDb extends Zend_File_Transfer_Adapter_Http
{
	/**
	 * Column name in table with foreign key to FilePeer.
	 * 
	 * @var Crud_Db_Table_Column_Abstract
	 */
	protected $_column;
	
	/**
	 * @var Crud_Db_Table_Row
	 */
	protected $_row;
	
	
	public function __construct(Crud_Db_Table_Column $column, $options = array())
	{
		$this->_column = $column;
		parent::__construct($options);
	}
	
	
    /**
     * Receive the file from the client (Upload).
     * And save metainformation in Database.
     *
     * @return boolean
     */
    public function receive($files = null)
	{
		/**
		 * 1. Файл заливается через форму и создается новая запись в бд.
		 * 2. Файл заливается через форму и он уже существует, поэтому возвращается существующий.
		 * 
		 * 3. Файл заливается через форму, до этого уже существовал файл, привязанный к этой записи,
		 * мы проверяем, привязан ли файл к чему-нибудь еще, 
		 * если нет - удаляем старый и создаем новую запись, 
		 * если да, то обновляем сущесвующий файл.
		 * 
		 * 
		 * Делаем так.
		 * Одна запись в таблице файл связана только с одной табличкой.
		 * Но несколько записей в File могут указывать на один и тот же физический файл.
		 * 
		 * При удалении физический файл не удаляется. Хмм.
		 * 
		 * 
		 * Если мы храним просто ссылки.
		 * Несколько ссылок на один и тот-же файл недопустимо, 
		 * потому-что мы знаем, где еще на этот же файл ссылка.
		 * При заливке идентичного файла мы тоже не узнаем, что у нас такой уже есть.
		 * 
		 * 
		 */
		$filePeer = FilePeer::getInstance();
		$column = $this->_column;
		

		// Вначале запоминает объект файла, на который сейчас стоит ссылка
		$row = $this->getDefaultRow();
		$fileForDelete = null;
		if (!$row->isNew()) {
			$fileForDeleteId = $row->getColumnValue($column);
			$fileForDelete = $filePeer->find($fileForDeleteId)->current();
		}
		
		// Далее мы должны получить нужную запись в file.
		// Пробуем получить уже существующий по хешу.
		$hash = $this->getHash('md5', $files);
		
		// Если это хеш уже сущесвующего файла - мы ничего не делаем.
		if ($fileForDelete && $fileForDelete->getHash() == $hash) {
			return true;
		}
		
		$fileRow = $filePeer->findByHash($hash)->current();
		if (!$fileRow) {
			// Если по хешу не получили - создаем новый.
			$fileRow = $filePeer->createRow();
		}
		
		// Если это новый файл - сохраняем его
		$fileRow->setDeleted(0);
		if (!$fileRow->getId()) {
			$ext = $this->getExtension($files);
			$info = current($this->getFileInfo($files));
			$size = $info['size'];
			
			$fileRow->setHash($hash);
			$fileRow->setExt($ext);
			$fileRow->setSize($size);
			$fileRow->setUri("$hash.$ext");
		}
		$fileRow->save();
		
		// Меняем ссылку из нашей таблицы на этот файл
		$row->setColumnValue($column, $fileRow->getId());
		
		// Запускаем удаление для старого файла. 
		// Если он привязан еще к чему-то, оно не пройдет.
		if ($fileForDelete) {
			try {
				$fileForDelete->setDeleted(1);
				$fileForDelete->save();
			} catch (Zend_Db_Exception $e) {}
		}
		
		// Добавляем фильтр на переименование файла
		$filter = new Zend_Filter_File_Rename("$hash.$ext");
		$this->addFilter($filter, null, $files);
		
		// И теперь перемещаем залитый файл в нужное место
		$result = parent::receive($files);
		return $result;
	}


	/**
	 * Set default row for update file information.
	 * 
	 * @param Crud_Db_Table_Row $row
	 * @return void
	 */
	public function setDefaultRow(Crud_Db_Table_Row $row)
	{
		$this->_row = $row;
	}
	
	/**
	 * Return default row for update file information.
	 * 
	 * @return Crud_Db_Table_Row
	 */
	public function getDefaultRow()
	{
		return $this->_row;
	}
	
	/**
	 * Return extenstion string.
	 * 
	 * @param string $file File name.
	 * @return string
	 * @throws File_Transfer_Exception
	 */
	public function getExtension($file)
	{
		$info = current($this->getFileInfo($file));
		$name = $info['name'];
		preg_match('#\.([a-z]{2,4}$)#s', $name, $result);
		if (!isset($result[1])) {
			throw new File_Transfer_Exception("Cant define extension of uploaded file: `$name`");
		}
		
		return $result[1];
	}
}